home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 007 / turboinc.arc / FILESYS.INC next >
Text File  |  1985-09-25  |  21KB  |  735 lines

  1. procedure filesys;
  2.  
  3.   const
  4.     mostfiles = 40;
  5.     soh = 1;
  6.     eot = 4;
  7.     ack = 6;
  8.     nak = $15;
  9.     can = $18;
  10.     C = $43;
  11.     drivecap = 191; {Kbyte capacity of files drive}
  12.     ksize = 1; {minimum increment of file size in Kbytes}
  13.  
  14.   type
  15.     filerec = record
  16.                title: name;
  17.                submit: integer;
  18.                date: name;
  19.                size: integer;
  20.                accesses: integer;
  21.                ASCII: boolean;
  22.                section: byte;
  23.                public: boolean;
  24.              end;
  25.     channel = array[0..127] of byte;
  26.  
  27.   var
  28.     filefile: file of filerec;
  29.     filetab: array[0..mostfiles] of filerec;
  30.     filebuff: array [0..16] of channel;
  31.     datafile: file;
  32.     chksum: byte;
  33.     CRC: integer;
  34.     crcmode: boolean;
  35.     enddir: integer;
  36.     comch: char;
  37.  
  38.   procedure xmit(x:byte);
  39.  
  40.     begin
  41.       xmitchar(chr(x));
  42.     end;
  43.  
  44.   function inbyte: byte;
  45.  
  46.     var temp: char;
  47.  
  48.     begin
  49.       repeat until inready or not cts;
  50.       if keypressed then read(kbd, temp) else temp := recvchar;
  51.       inbyte := ord(temp);
  52.     end;
  53.  
  54.   procedure calcCRC(data:byte);
  55.  
  56.     var
  57.       carry: boolean;
  58.       i: byte;
  59.  
  60.     begin
  61.       chksum := lo(chksum + data);
  62.       for i := 0 to 7 do begin
  63.         carry := (crc and $8000) <> 0;
  64.         crc := crc shl 1;
  65.         if (data and $80) <> 0 then crc := crc or $0001;
  66.         if carry then crc := crc xor $1021;
  67.         data := lo(data shl 1);
  68.       end;
  69.     end;
  70.  
  71.   procedure sendcalc(ch : byte);
  72.  
  73.     begin
  74.       xmit(ch);
  75.       calcCRC(ch);
  76.     end;
  77.  
  78.   procedure acknak(var inch: byte; time: integer);
  79.  
  80.     var loop, loopend: integer;
  81.  
  82.     begin
  83.       loopend := 100 * time;
  84.       loop := 0;
  85.       inch := 0;
  86.       repeat
  87.         delay(10);
  88.         if inready then inch := inbyte;
  89.         loop :=loop + 1;
  90.       until (inch in [ack, nak, can, C]) or (loop >= loopend) or not cts;
  91.     end;
  92.  
  93.   function acknakout(ch : byte): boolean;
  94.  
  95.     var  times, loops: integer;
  96.  
  97.     begin
  98.       times := 0;
  99.       repeat
  100.         loops := 0;
  101.         xmit(ch);
  102.         while (loops < 10) and not timedin do loops := loops + 1;
  103.         times := times + 1;
  104.       until inready or (times > 9) or not cts;
  105.       acknakout := inready and cts;
  106.     end;
  107.  
  108.   procedure download(var successful: boolean);
  109.  
  110.     var
  111.       inch, loop: byte;
  112.       blocknum, period, tries: integer;
  113.       done: boolean;
  114.       temp: line;
  115.  
  116.     begin
  117.       reset(datafile);
  118.       str(filesize(datafile):4, temp);
  119.       lineout('Ready for XMODEM transfer:');
  120.       lineout('File open:' + temp + ' records;');
  121.       lineout('To cancel: type CTL-X until you return to command prompt.');
  122.       blockread(datafile, filebuff[0], 1);
  123.       done := false;
  124.       tries := 0;
  125.       blocknum := 1;
  126.       crcmode := false;
  127.       repeat
  128.         acknak(inch, 60);
  129.         if inch = 0 then inch := can;
  130.         if inch = C then begin
  131.           crcmode := true;
  132.           writeln('CRC mode requested');
  133.         end;
  134.         if inch = ack then begin
  135.           if eof(datafile) then done := true else begin
  136.             write(cr + 'Sent #', blocknum:4);
  137.             blockread(datafile, filebuff[0], 1);
  138.             blocknum := blocknum + 1;
  139.             tries := 0;
  140.           end;
  141.         end
  142.         else tries := tries + 1;
  143.         if (inch <> can) and cts and not done then begin
  144.           xmit(soh);
  145.           xmit(lo(blocknum));
  146.           xmit(255-lo(blocknum));
  147.           chksum := 0;
  148.           crc := 0;
  149.           for loop := 0 to 127 do sendcalc(filebuff[0][loop]);
  150.           calcCRC(0);
  151.           calcCRC(0);
  152.           if crcmode then begin xmit(hi(crc)); xmit(lo(crc)); end
  153.             else xmit(chksum);
  154.         end;
  155.         if tries = 5 then crcmode := not crcmode;
  156.       until (inch = can) or done or (tries= 10) or not cts;
  157.       successful := done;
  158.       tries := 0;
  159.       if successful and cts then repeat
  160.         xmit(eot);
  161.         acknak(inch, 10);
  162.         tries := tries + 1;
  163.       until (inch=ack) or (tries > 10) or not cts;
  164.       if cts and (inch <> can) and not successful then xmit(can);
  165.       close(datafile);
  166.     end;
  167.  
  168.   function recchar(var error: boolean): byte;
  169.  
  170.     var temp: byte;
  171.  
  172.     begin
  173.       temp := 0;
  174.       if not cts then error := true;
  175.       if not error then begin
  176.         if not timedin then error := true
  177.         else begin
  178.           temp := inbyte;
  179.           calcCRC(temp);
  180.           recchar := temp;
  181.         end;
  182.       end;
  183.     end;
  184.  
  185.   procedure clearline;
  186.  
  187.     var junk: byte;
  188.  
  189.     begin
  190.       while timedin do junk := inbyte;
  191.     end;
  192.  
  193. {$I-}
  194.   procedure upload(var successful: boolean);
  195.  
  196.     var
  197.       blocknum, tries, byteloc : integer;
  198.       comp, locblock, crc2     : integer;
  199.       fatal, error, done       : boolean;
  200.       opening, inch, locrc     : byte;
  201.       hicrc, csum2, mode       : byte;
  202.  
  203.     begin
  204.       lineout('Beginning XMODEM protocol upload:');
  205.       lineout('To cancel: type CTRL-X until you return to command prompt.');
  206.       tries := 0;
  207.       done := false;
  208.       opening := 0;
  209.       locblock := 1;
  210.       rewrite(datafile);
  211.       fatal := ioresult > 0;
  212.       if crcmode then mode := C else mode := nak;
  213.       if cts and not fatal then fatal := not acknakout(mode);
  214.       while cts and not (done or fatal) do begin
  215.         tries := tries + 1;
  216.         error := false;
  217.         opening := recchar(error);
  218.         if opening = can then fatal := true;
  219.         if opening = eot then done := true;
  220.         if (opening <> eot) and (opening <> soh) and not fatal
  221.           then error := true;
  222.         if cts and not (error or fatal or done) then begin
  223.           blocknum := recchar(error);
  224.           comp := recchar(error);
  225.           if lo(comp + blocknum + opening) <> 0 then error := true;
  226.           byteloc := 0;
  227.           crc := 0;
  228.           chksum := 0;
  229.           while (byteloc < 128) and not (error or fatal) do begin
  230.             filebuff[0][byteloc] := recchar(error);
  231.             byteloc := byteloc + 1;
  232.           end;
  233.           if cts and not (error or fatal) then begin
  234.             calcCRC(0);
  235.             calcCRC(0);
  236.             crc2 := crc;
  237.             csum2 := chksum;
  238.             hicrc := recchar(error);
  239.             if crcmode then begin
  240.               locrc := recchar(error);
  241.               if (lo(crc2) <> locrc) or (hi(crc2) <> hicrc) then error := true;
  242.             end else if csum2 <> hicrc then error := true;
  243.             if (lo(locblock) <> blocknum)
  244.               and (lo(locblock) <> lo(blocknum+1))
  245.               and not error
  246.               then fatal := true;
  247.             if (lo(locblock) = blocknum) and not (error or fatal) then begin
  248.               blockwrite(datafile, filebuff[0], 1);
  249.               write(cr + ' Received #', blocknum:4);
  250.               if IOresult <> 0 then fatal := true;
  251.               tries := 0;
  252.               locblock := locblock + 1;
  253.             end;
  254.           end;
  255.         end;
  256.         if not (fatal or error) then flush else clearline;
  257.         if done or not (error or fatal) then fatal := not acknakout(ack);
  258.         if error and not fatal then begin
  259.           fatal := not acknakout(nak);
  260.           if tries > 6 then crcmode := not crcmode;
  261.         end;
  262.       end;
  263.       if fatal then xmit(can);
  264.       if done then xmit(ack);
  265.       close(datafile);
  266.       successful := (IOresult = 0) and done and not fatal;
  267.       if not successful then erase(datafile);
  268.     end;
  269.  
  270.   procedure storebuff(var buffernum: byte; var paused, aborted: boolean);
  271.  
  272.     var loop: byte;
  273.  
  274.     begin
  275.       loop := 0;
  276.       while (loop < buffernum) and not aborted do begin
  277.         blockwrite(datafile, filebuff[loop], 1);
  278.         if IOresult > 0 then aborted := true;
  279.         loop := loop + 1;
  280.       end;
  281.       if buffernum in [1..16] then filebuff[0] := filebuff[buffernum];
  282.       buffernum := 0;
  283.       repeat xmit(17) until timedin;
  284.       paused := false;
  285.     end;
  286.  
  287.   procedure textcap(var successful: boolean);
  288.  
  289.     var
  290.       buffernum, where, loop  : byte;
  291.       cc, cz, paused          : boolean;
  292.       withecho, done, aborted : boolean;
  293.       temp                    : byte;
  294.  
  295.     begin
  296.       withecho := (getcap('Do you want your text echoed (Y/N) ? ') = 'Y');
  297.       lineout('Beginning text capture: two CTRL-Cs abort, two CTRL-Zs end.');
  298.       cc := false;
  299.       cz := false;
  300.       done := false;
  301.       paused := false;
  302.       buffernum := 0;
  303.       where := 0;
  304.       rewrite(datafile);
  305.       aborted := (IOresult > 0);
  306.       while cts and not (done or aborted) do begin
  307.         if paused then
  308.           if not timedin then storebuff(buffernum, paused, aborted);
  309.         temp := inbyte;
  310.         if not cts then aborted := true;
  311.         if withecho and outready then xmit(temp);
  312.         if temp = 3 then begin if cc then aborted := true else cc := true; end
  313.           else cc := false;
  314.         if temp = 26 then begin if cz then done := true else cz := true; end
  315.           else cz := false;
  316.         filebuff[buffernum][where] := temp;
  317.         where := where + 1;
  318.         if where > 127 then begin
  319.           where := 0;
  320.           buffernum := buffernum + 1;
  321.         end;
  322.         if buffernum > 14 then begin
  323.           xmit(19);
  324.           paused := true;
  325.         end;
  326.         if buffernum > 16 then aborted := true;
  327.       end;
  328.       if done and cts and not aborted then begin
  329.         buffernum := buffernum + 1;
  330.         storebuff(buffernum, paused, aborted);
  331.       end;
  332.       close(datafile);
  333.       if aborted and (IOresult = 0) then erase(datafile);
  334.     successful := done and (IOresult=0) and not aborted;
  335.     end;
  336. {$I+}
  337.  
  338.   function exists(filename: name): boolean;
  339.  
  340.     var found: boolean;
  341.  
  342.     begin
  343.       assign(datafile, filename);
  344.       {$I-} reset(datafile) {$I+};
  345.       found := (IOresult = 0);
  346.       if found then close(datafile);
  347.       exists := found;
  348.     end;
  349.  
  350.   function alpha(filename: name): boolean;
  351.  
  352.     var strpos: integer;
  353.         okay:   boolean;
  354.         dots:   byte;
  355.  
  356.     begin
  357.       dots := 0;
  358.       alpha := true;
  359.       if length(filename) > 0 then
  360.         for strpos := 1 to length(filename) do begin
  361.           if filename[strpos] = '.' then dots := dots + 1;
  362.           if not (filename[strpos] in ['.', '-', '_', '0'..'9', 'A'..'Z'])
  363.             then alpha := false;
  364.         end;
  365.       if dots > 1 then alpha := false;
  366.     end;
  367.  
  368.   function getlegal: name;
  369.  
  370.     var filename:  name;
  371.         dotpos: integer;
  372.  
  373.     begin
  374.       repeat
  375.         filename := allcaps(getinput('Enter name of file ? ', 12, echo));
  376.         dotpos := pos('.', filename);
  377.       until ((dotpos < 10) and (dotpos <> 1)
  378.        and (not((dotpos = 0) and (length(filename) > 8)))
  379.        and (not((dotpos > 0) and (length(filename) > dotpos + 3)))
  380.        and alpha(filename))
  381.        or (filename = '');
  382.       getlegal := filename;
  383.     end;
  384.  
  385.   function dirpos(filename: name): integer;
  386.  
  387.     var loopvar: integer;
  388.  
  389.     begin
  390.       dirpos := 0;
  391.       loopvar := 0;
  392.       repeat
  393.         loopvar := loopvar + 1;
  394.       until (filetab[loopvar].title = filename) or (loopvar >= enddir);
  395.     if filetab[loopvar].title = filename then dirpos := loopvar;
  396.     end;
  397.  
  398.   function getsect: byte;
  399.  
  400.     var temp: integer;
  401.  
  402.     begin
  403.       if sectsin then repeat
  404.         temp := getint(numsects, 0, 'Which section (0 for all, ? for list) ? ');
  405.         if temp = -1 then listsections else getsect := temp;
  406.       until (temp <> -1) or not cts
  407.       else getsect := 1;
  408.     end;
  409.  
  410.   procedure addfile(filename: name; sectnum: byte; xmodem: boolean);
  411.  
  412.     begin
  413.       with filetab[enddir + 1] do begin
  414.         title := filename;
  415.         submit := usernum;
  416.         if clockin then date := timeon;
  417.         assign(datafile, filedrive + filename);
  418.         reset(datafile);
  419.         size := filesize(datafile);
  420.         close(datafile);
  421.         accesses := 0;
  422.         ASCII := not xmodem;
  423.         section := sectnum;
  424.         public := false;
  425.       end;
  426.     end;
  427.  
  428.   procedure newfile(xmodem: boolean);
  429.  
  430.     var
  431.       filename: name;
  432.       successful: boolean;
  433.       sectnum: byte;
  434.  
  435.     begin
  436.       clearsc;
  437.       if enddir >= mostfiles then lineout('No file space available.')
  438.       else begin
  439.         stringout('Upload: ');
  440.         filename := getlegal;
  441.         if filename <> '' then begin
  442.           if exists(filedrive + filename) then lineout('File name in use.')
  443.           else begin
  444.             repeat sectnum := getsect until (sectnum <> 0) or not cts;
  445.             assign(datafile, filedrive + filename);
  446.             if cts then begin
  447.               if xmodem then upload(successful)
  448.                 else textcap(successful);
  449.               if successful then addfile(filename, sectnum, xmodem);
  450.               clearline;
  451.               if successful then enddir := enddir + 1
  452.                 else lineout('Fatal transfer error or disk full...');
  453.             end;
  454.           end;
  455.         end;
  456.       end;
  457.     end;
  458.  
  459.   function legaltab(prompt: line): integer;
  460.  
  461.     var filename: name;
  462.         tabloc:   integer;
  463.  
  464.     begin
  465.       tabloc := 0;
  466.       clearsc;
  467.       stringout(prompt);
  468.       filename := getlegal;
  469.       if filename <> '' then begin
  470.         tabloc := dirpos(filename);
  471.         if tabloc <> 0 then
  472.           if not (filetab[tabloc].public or (access > reg)) then tabloc := 0;
  473.         if tabloc <> 0 then assign(datafile, filedrive + filename)
  474.           else if filename <> '' then lineout('No such file available.');
  475.       end;
  476.       legaltab := tabloc;
  477.     end;
  478.  
  479.   procedure transmitfile;
  480.  
  481.     var
  482.       successful: boolean;
  483.       tabloc: integer;
  484.  
  485.     begin
  486.       tabloc := legaltab('Download: ');
  487.       if tabloc > 0 then begin
  488.         download(successful);
  489.         if successful then with filetab[tabloc] do
  490.           accesses := accesses + 1
  491.         else lineout('Transfer failed.');
  492.       end;
  493.     end;
  494.  
  495.   procedure textdump;
  496.  
  497.     var
  498.       tabloc : integer;
  499.       libname: longname;
  500.  
  501.     begin
  502.       tabloc := legaltab('ASCII text dump: ');
  503.       lineout(space);
  504.       if tabloc > 0 then with filetab[tabloc] do begin
  505.         libname := title;
  506.         if copy(title, pos('.', title), 4) = '.LBR' then begin
  507.           lineout(title + ' is a library file: please select a member: ');
  508.           libname := getlegal;
  509.           if libname = '' then libname := 'DIR';
  510.           libname := copy(title, 1, length(title)-4) + '/' + libname;
  511.         end;
  512.         typefile(filedrive + libname, false);
  513.         if not cancelled then accesses := accesses + 1;
  514.       end;
  515.     end;
  516.  
  517.   procedure showspace;
  518.  
  519.     var  loop, howbig, howmuch, sectmin : integer;
  520.          temp : line;
  521.  
  522.     begin
  523.       sectmin := ksize shl 3;
  524.       howmuch := drivecap;
  525.       if enddir > 0 then for loop := 1 to enddir do
  526.        with filetab[loop] do begin
  527.         howbig := (size + sectmin - 1) div sectmin;
  528.         howmuch := howmuch - howbig;
  529.       end;
  530.       str(howmuch:4, temp);
  531.       if cts then lineout(cr + lf + temp + 'K space remaining.');
  532.     end;
  533.  
  534.   procedure dir(sectnum: byte);
  535.  
  536.     var loop, spaces : byte;
  537.         howbig, sectmin : integer;
  538.         any  : boolean;
  539.         temp : line;
  540.  
  541.     begin
  542.       any := false;
  543.       sectmin := ksize shl 3;
  544.       lineout(space);
  545.       if sectsin then lineout('Section ' + sect[sectnum] + ':');
  546.       if enddir > 0 then for loop := 1 to enddir do with filetab[loop] do begin
  547.         howbig := (size + sectmin - 1) div sectmin;
  548.         if cts and (public or (access = sysop) or (submit = usernum))
  549.          and (sectnum = section) then begin
  550.           str(howbig:4, temp);
  551.           for spaces := length(title) to 13 do temp := ' ' + temp;
  552.           stringout(title + temp + 'K');
  553.           if clockin then stringout('   ' + date);
  554.           if not public then stringout('  * Private *');
  555.           lineout(space);
  556.           if (access = sysop) or (submit = usernum) then begin
  557.             str(accesses:4, temp);
  558.             lineout('Accesses: ' + temp + '    From: ' + getname(submit));
  559.           end;
  560.           any := true;
  561.         end;
  562.       end;
  563.       if cts and not any then lineout('No files found.');
  564.     end;
  565.  
  566.   procedure directory;
  567.  
  568.     var sectnum : byte;
  569.  
  570.     begin
  571.       stringout('Directory: ');
  572.       sectnum := getsect;
  573.       if sectnum > 0 then dir(sectnum)
  574.         else for sectnum := 1 to numsects do dir(sectnum);
  575.       showspace;
  576.     end;
  577.  
  578.   procedure ldir;
  579.  
  580.     var
  581.       tabloc : integer;
  582.  
  583.     begin
  584.       tabloc := legaltab('Library directory: ');
  585.       lineout(space);
  586.       if tabloc > 0 then typefile(filedrive + filetab[tabloc].title + '/DIR', false);
  587.     end;
  588.  
  589.   procedure killfile;
  590.  
  591.     var loop, tabloc: integer;
  592.  
  593.     begin
  594.       tabloc := legaltab('Delete: ');
  595.       if tabloc > 0 then begin
  596.         erase(datafile);
  597.         if enddir > tabloc then for loop := tabloc + 1 to enddir do
  598.           filetab[loop - 1] := filetab[loop];
  599.         enddir := enddir - 1;
  600.       end;
  601.     end;
  602.  
  603.   procedure installfile;
  604.  
  605.     var filename : name;
  606.         sectnum  : byte;
  607.  
  608.     begin
  609.       if enddir < mostfiles then begin
  610.         filename := getlegal;
  611.         if filename <> '' then begin
  612.           if exists(filedrive+filename) and (dirpos(filename) = 0) then begin
  613.             repeat sectnum := getsect until (sectnum <> 0) or not cts;
  614.             addfile(filename, sectnum, true);
  615.             enddir := enddir + 1;
  616.             lineout('File installed.');
  617.           end;
  618.         end;
  619.       end;
  620.     end;
  621.  
  622.   function newname(tabloc: integer): name;
  623.  
  624.     var filename: name;
  625.  
  626.     begin
  627.       newname := filetab[tabloc].title;
  628.       stringout('New name? ');
  629.       filename := getlegal;
  630.       if (filename <> '') then begin
  631.         if not exists(filedrive + filename) then begin
  632.           assign(datafile, filedrive + filetab[tabloc].title);
  633.           rename(datafile, filename);
  634.           newname := filename;
  635.           stringout('File renamed.');
  636.         end
  637.         else lineout('Name in use - cannot rename.');
  638.       end;
  639.     end;
  640.  
  641.  
  642.   procedure editheader;
  643.  
  644.     var tabloc: integer;
  645.         filename: name;
  646.         innum: integer;
  647.         sectstring: name;
  648.  
  649.     begin
  650.       tabloc := legaltab('Edit: ');
  651.       if tabloc > 0 then with filetab[tabloc] do begin
  652.         repeat
  653.           str(section:3, sectstring);
  654.           lineout(space);
  655.           lineout('1- Name    : ' + title);
  656.           lineout('2- From    : ' + getname(submit));
  657.           lineout('3- Section : ' + sectstring);
  658.           lineout('4- Public? : ' + yn[public]);
  659.           lineout(space);
  660.           innum := getint(4, 0, 'Number of parameter to change? ');
  661.           case innum of
  662.             1: title := newname(tabloc);
  663.             2: submit := getid('Name of submitter? ');
  664.             3: repeat section := getsect until (section <> 0) or not cts;
  665.             4: public := not public;
  666.           end;
  667.         until (innum = 0) or not cts;
  668.         assign(datafile, filedrive + title);
  669.         reset(datafile);
  670.         size := filesize(datafile);
  671.         close(datafile);
  672.       end else lineout('File not in directory.');
  673.     end;
  674.  
  675.   procedure initfile;
  676.  
  677.     var
  678.       loopvar: integer;
  679.       temp: name;
  680.  
  681.     begin
  682.       lineout('Initializing file system...');
  683.       loopvar := 0;
  684.       assign(filefile, 'FILES.BBS');
  685.       {$I-} reset(filefile) {$I+};
  686.       if IOresult = 0 then begin
  687.         while not eof(filefile) do begin
  688.           loopvar := loopvar + 1;
  689.           read(filefile, filetab[loopvar]);
  690.         end;
  691.         close(filefile);
  692.       end;
  693.       enddir := loopvar;
  694.       filesopen := true;
  695.     end;
  696.  
  697.   procedure closefile;
  698.  
  699.     var loopvar: integer;
  700.  
  701.     begin
  702.       rewrite(filefile);
  703.       if enddir > 0 then
  704.         for loopvar := 1 to enddir do write(filefile, filetab[loopvar]);
  705.       close(filefile);
  706.       filesopen := false;
  707.     end;
  708.  
  709.   begin
  710.     clearsc;
  711.     initfile;
  712.     if not expert then outfile(filemenu);
  713.     repeat
  714.       lineout(space);
  715.       comch := getcap('Files command (or ? for menu) ? ');
  716.       case comch of
  717.        'D' : directory;
  718.        'S' : transmitfile;
  719.        'T' : textdump;
  720.        'H' : outfile(filehelp);
  721.        'G' : disconnect;
  722.        '?' : outfile(filemenu);
  723.        'L' : ldir;
  724.        'U' : if access>newuser then begin crcmode := true; newfile(true); end;
  725.        'C' : if access>newuser then begin crcmode := false; newfile(true); end;
  726.        'V' : if access>newuser then newfile(false);
  727.        'K' : if access = sysop then killfile;
  728.        'I' : if access = sysop then installfile;
  729.        'E' : if access = sysop then editheader;
  730.       end;
  731.     until (comch = 'Q') or not cts;
  732.     if cts then lineout('Closing file system...');
  733.     closefile;
  734.   end;
  735.